#pragma once
#include <iostream>
#include <unordered_map>
#include "channel.hpp"

#define MAX_EPOLLEVENTS 1024

class EventLoop;

class Poller {
    private:
        int _epfd;
        struct epoll_event _evs[MAX_EPOLLEVENTS];
        std::unordered_map<int, Channel*> _channels;
        EventLoop *_loop;
    private:
        void Poller::update(int op, Channel *channel) {
            struct epoll_event ev;
            ev.events = channel->events();
            ev.data.fd = channel->fd();
            epoll_ctl(_epfd, op, ev.data.fd, &ev);
        }
    public:
        Poller::Poller(EventLoop *loop): _loop(loop), _epfd(-1) {
            _epfd = epoll_create(MAX_EPOLLEVENTS);
            if (_epfd < 0) {
                perror("create epoll failed!!");
                abort();
            }
        }
        bool Poller::has_channel(Channel *channel) {
            int fd = channel->fd();
            auto it = _channels.find(fd);
            if (it == _channels.end()) {
                return false;
            }
            return true;
        }
        void Poller::update_channel(Channel *channel) {
            if (has_channel(channel)) {
                return update(EPOLL_CTL_MOD, channel);
            }
            _channels[channel->fd()] = channel;
            return update(EPOLL_CTL_ADD, channel);
        }
        void Poller::remove_channel(Channel *channel) {
            /*这边后边还要修改，应该在没有事件后删除，要根据channel的状态来决定*/
            auto it = _channels.find(channel->fd());
            if (it != _channels.end()) {
                _channels.erase(it);
            }
            return update(EPOLL_CTL_DEL, channel);
        }
        bool Poller::poll(std::vector<Channel*> *active_channels, int timeout = -1) {
            active_channels->clear();
            int nfds = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, timeout);
            if (nfds < 0) {
                if (errno == EINTR) {
                    return true;
                }
                perror("epoll wait error!!");
                return false;
            }else if (nfds == 0) {
                return true;
            }
            for (int i = 0; i < nfds; i++) {
                int fd = _evs[i].data.fd;
                auto it = _channels.find(fd);
                assert(it != _channels.end());
                it->second->set_revents(_evs[i].events);
                active_channels->push_back(it->second);
            }
            return true;
        }
};